﻿using System.Configuration;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using Ipmce.RemoteVoting.Common.Tools;
using Ipmce.RemoteVoting.Common.Tools.CardReader;
using Ipmce.RemoteVoting.Common.Tools.CardReader.ImageParsing;
using Ipmce.RemoteVoting.Frontend.VotingApplication.Utils;
using Ipmce.RemoteVoting.Frontend.VotingApplication.ViewModel;
using Ipmce.RemoteVoting.Frontend.VotingLibrary;
using Microsoft.Practices.Unity;

namespace Ipmce.RemoteVoting.Frontend.VotingApplication
{
	/// <summary>
	/// Interaction logic for App.xaml
	/// </summary>
	public partial class App
	{
		static App()
		{
			ServicePointManager.ServerCertificateValidationCallback =
				(sender, certificate, chain, policy) => CheckCertificate(certificate);
		}

		public App()
		{
			DispatcherUnhandledException += App_DispatcherUnhandledException;
		}

// ReSharper disable InconsistentNaming
		private static void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
// ReSharper restore InconsistentNaming
		{
			var builder = new StringBuilder();
			builder.AppendFormat("Exception: {0}", e.Exception);
			//if (e.Exception.InnerException != null)
			//{
			//    builder.Append(Environment.NewLine);
			//    builder.AppendFormat("Inner exception: {0}", e.Exception.InnerException);
			//}
			MessageBox.Show(builder.ToString(), "Случилось страшное!", MessageBoxButton.OK, MessageBoxImage.Error);
		}

		private static readonly string RemoteVotingRootCa = ConfigurationManager.AppSettings["rootCaName"];

		protected override void OnStartup(StartupEventArgs e)
		{
			base.OnStartup(e);

			_container.RegisterType<ICertificateDataProvider, CertificateAuthorizationViewModel>()
				.RegisterType<IDateTimeProvider, NotifyingDateTimeViewModel>()
				.RegisterType<IPassportDataProvider, PassportAuthorizationViewModel>()
				.RegisterType<IVote, VoteImpl>()
				.RegisterType<IPassportReader, PassportReaderFacade>()
				.RegisterType<IPasswordCreator, PasswordCreator>()
				.RegisterType<ICertificateProvider, CertificateProvider>(
					new InjectionFactory(c => new CertificateProvider(RemoteVotingRootCa)))
				.RegisterType<ICandidateListProvider, CandidateListProvider>()
				.RegisterType<IVoteEncryptor, VoteEncryptor>(new InjectionFactory(
						c => new VoteEncryptor(new X509Certificate2(VotingApplication.Properties.Resources.VotingEncryptionCertificate))))
				.RegisterType<IConfirmationIdCreator, ConfirmationIdCreator>()
				.RegisterType<MainWindowViewModel>(new InjectionFactory(CreateMainViewModel))
				.RegisterType<IImageParser, BiometricInformationManipulator>();

			var mainWindow = new MainWindow
			                 	{
									DataContext = _container.Resolve<MainWindowViewModel>()
			                 	};
			mainWindow.Show();
		}

		protected override void OnExit(ExitEventArgs e)
		{
			base.OnExit(e);
			_container.Dispose();
		}

        private static MainWindowViewModel CreateMainViewModel(IUnityContainer container)
        {
            try
            {
                var candidateList = container.Resolve<ICandidateListProvider>().GetCandidateList();
                return new MainWindowViewModel(container.Resolve<ICertificateDataProvider>(),
                    container.Resolve<IPassportDataProvider>(), container.Resolve<IDateTimeProvider>(),
                    container.Resolve<IVote>(), candidateList, container.Resolve<IConfirmationIdCreator>());
            }
            catch (UnableToProvideCandidateListException)
            {
                MessageBox.Show("Невозможно подсоедениться к серверу для получения списка кандидатов.", "Ошибка",
                                MessageBoxButton.OK, MessageBoxImage.Error);
                throw;
            }
        }

		private static bool CheckCertificate(X509Certificate certificate)
		{
			return certificate.Issuer == "CN=" + RemoteVotingRootCa;
		}

		private readonly IUnityContainer _container = new UnityContainer();
	}
}
